package genome;


import java.util.*;

import tool.RandomGenerator;
import tool.RepeatRandom;
import tool.Utility;


public class IG extends Genotype{
	
	private RepeatRandom r = RandomGenerator.R;
	
	public static double MUTATION_RATE = GenomeParameters.GGT_MUTATION_RATE;
	public static int MX_VAL = GenomeParameters.GGT_MAX_VAL;
	
	public IG(){
		this(GenomeParameters.IG_SIZE);
	}
	
	public IG(int sz){
		super(new double[1],sz);
		for(int i=0;i<sz;i++){
			genome[i] = r.nextInt(MX_VAL);
		}
	}

	@Override
	public double eval() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public String getConstantString() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Genotype getCopy() {
		IG b = new IG(this.size);
		for(int i=0;i<b.size;i++){
			b.genome[i] = this.genome[i];
		}
		return b;
	}

	@Override
	public Genotype pointMutate() {
		IG g = (IG)this.getCopy();
		int i = r.nextInt(size);
		boolean done =false;
		while(!done){
			int k = r.nextInt(MX_VAL);
			if(g.genome[i]!=k){
				g.genome[i] = k; done=true;
			}
		}
		return g;
	}
	
	public Genotype stoMutate(){
		IG g = (IG)this.getCopy();
		for(int i=0;i<size;i++){
			if(r.nextDouble()<MUTATION_RATE){
				boolean done = false;
				while(!done){
					int k = r.nextInt(MX_VAL);
					if(g.genome[i]!=k){
						g.genome[i] = k; done=true;
					}
				}
			}
		}
		return g;
	}

	@Override
	public void setConstants(double[] d) {
		// TODO Auto-generated method stub

	}

	@Override
	public String toMathString() {
		return this.toString();
	}
	
	public static void main(String args[]){
		IG g = new IG(6);
		g.printGenome();
		IG g2 = (IG)g.pointMutate();
		g2.printGenome();
		g.printGenome();
	}

	@Override
	public double[] toVector() {
		/*//currently just returns the sum
		int sum = 0;
		for (int i = 0; i < genome.length; i++) {
			sum = sum+genome[i];
		}
		int[] v = {sum};
		return v;*/
		
		//test trigonometric fn.
		double sum = 0.0;
		for (int i = 0; i < genome.length; i++) {
			sum = sum+Math.sin(genome[i]);
		}
		double[] v = {sum};
		return v;
	}

	@Override
	public Genotype increment() {
		IG g = (IG)this.getCopy();
		
		boolean incremented = false;
		int i=0;
		while(!incremented && i<g.size){
			if(g.genome[i]<MX_VAL){
				g.genome[i] = g.genome[i]+1;
				incremented = true;
			}
			else {
				g.genome[i] = 0; i=i+1;
			}
		}
		return g;
	}

	@Override
	public ArrayList<Genotype> generateSpace() {
		ArrayList<Genotype> space = new ArrayList<Genotype>();
		
		IG g = new IG(this.size);
		g.clear(size);
		
		for(int i=0;i<Math.pow(MX_VAL+1, this.size);i++){
			space.add(g.getCopy());
			g = (IG)g.increment();
		}
		return space;
	}

	@Override
	public double[] getSymbolicValues() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public double distanceTo(Genotype g) {
		//euclidean distance
		g = (IG)g;
		double e = 0.0;
		for (int i = 0; i < g.genome.length; i++) {
			e = e+ Math.pow((this.genome[i]-g.genome[i]),2);
		}
		return Utility.roundToSignificantFigures(Math.sqrt(e),5);
	}

	@Override
	public ArrayList<Genotype> generateSpace(int samples) {
		ArrayList<Genotype> space = new ArrayList<Genotype>();
		
		for(int i=0;i<samples;i++){
			space.add(new IG(this.size));
		}
		return space;
	}

}
